#include <gflags/gflags.h>
#include <butil/logging.h>
#include <brpc/server.h>
#include <json2pb/pb_to_json.h>
#include "main.pb.h"
// 使用 gflags 定义一些命令行参数
DEFINE_int32(listen_port, 8000, "服务器地址信息");
DEFINE_int32(idle_timeout_s, -1, "空闲连接超时关闭时间：默认-1 表示不关闭");
DEFINE_int32(thread_count, 3, "服务器启动线程数量");
 
namespace example {
class EchoServiceImpl : public EchoService {
public:
 EchoServiceImpl() {}
 virtual ~EchoServiceImpl() {}
 // cntl_base：包含除了 request 和 response 之外的参数集合
 // request: 请求，只读的，来自 client 端的数据包
 // response: 回复。需要用户填充，如果存在 required 字段没有被设置，该次调用会失败。
 // done: done 由框架创建，递给服务回调，包含了调用服务回调后的后续动作，包括检查 response 正确性，序列化，打包，发送等逻辑。不管成功失败，done->Run()必须在请求处理完成后被用户调用一次。
 virtual void Echo(google::protobuf::RpcController* cntl_base,
 const EchoRequest* request,
 EchoResponse* response,
 google::protobuf::Closure* done) {
 // 类型于守卫锁，以 ARII 方式自动释放 done 对象
 brpc::ClosureGuard done_guard(done);
 brpc::Controller* cntl = static_cast<brpc::Controller*>(cntl_base);
 // 可选项： 本质是设置一个 hook 函数，在发送响应后及在cntl_base、request、response 释放之前调用
 cntl->set_after_rpc_resp_fn(std::bind(&EchoServiceImpl::CallAfterRpc,
 std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
 // 打印一些相关的参数日志信息
 std::cout << "请求内容：" << request->message() << std::endl;
 // 填充响应，客户端发送什么数据，服务器就回复什么数据
 response->set_message(request->message() + " Hello");
 } 
 // 可选项： 回调函数， 此时响应已经发回给客户端,但是相关结构还没释放
 static void CallAfterRpc(brpc::Controller* cntl,
 const google::protobuf::Message* req,
 const google::protobuf::Message* res) {
 std::string req_str;
 std::string res_str;
 json2pb::ProtoMessageToJson(*req, &req_str, NULL);
 json2pb::ProtoMessageToJson(*res, &res_str, NULL);
 std::cout << "req:" << req_str << std::endl;
 std::cout << "res:" << res_str << std::endl;
 } 
};
} // namespace example
int main(int argc, char* argv[]) {
 
 logging::LoggingSettings log_setting;
 log_setting.logging_dest = logging::LoggingDestination::LOG_TO_NONE;
 logging::InitLogging(log_setting);
 // 解析命令行参数
 google::ParseCommandLineFlags(&argc, &argv, true);
 // 定义服务器
 brpc::Server server;
 // 创建服务对象. 
 example::EchoServiceImpl echo_service_impl;
 // 将服务添加到服务器中
 if (server.AddService(&echo_service_impl, 
 brpc::SERVER_DOESNT_OWN_SERVICE) != 0) {
 std::cout << "add service failed!\n";
 return -1;
 } 
 // 开始运行服务器
 brpc::ServerOptions options;
 options.idle_timeout_sec = FLAGS_idle_timeout_s;
 options.num_threads = FLAGS_thread_count;
 if (server.Start(FLAGS_listen_port, &options) != 0) {
 std::cout << "Fail to start EchoServer";
 return -1;
 } 
 // 阻塞等待服务端运行 
 server.RunUntilAskedToQuit();
 return 0;
}